package xlsx

import (
	"bufio"
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
	"idle/utils/fileUtils"
	"idle/utils/stringUtils"
	"os"
	"path"
	"path/filepath"
	"strings"
	"text/template"
)

type Field struct {
	FieldDesc string //字段中文名
	FieldName string //字段英文名
	Typ       string //类型
	Desc      string //字段描述
	Commit    string //字段`json:`
}

type StructInfo struct {
	FileName       string
	FirstUpperName string
	FirstLowerName string
	Fields         []Field
}

func XlsxToGo(xlsxDir, goDir string) {
	paths, err := fileUtils.GetDirAllEntryPaths(xlsxDir, true)
	if err != nil {
		return
	}
	for _, fpath := range paths {
		if fileUtils.IsDir(fpath) {
			continue
		}
		fpath = filepath.ToSlash(fpath)
		fileName := path.Base(fpath)
		if strings.HasPrefix(fileName, "~") {
			continue
		}
		if path.Ext(fileName) != ".xlsx" {
			continue
		}
		GenGoFile(fpath, goDir)
	}

}

func GenGoFile(p string, goDir string) {
	structInfo := GetStructInfo(p)
	// 生成 Go 结构体字段定义代码
	tmpl, err := template.New("struct").Parse(`
package config

import (
	"github.com/360EntSecGroup-Skylar/excelize"
	"github.com/mitchellh/mapstructure"
	"idle/utils/configUtls"
	"log"
)

// {{.FileName}}
type {{.FirstUpperName}} struct {
{{- range .Fields}}
	{{.FieldName}} {{.Typ}} {{.Commit}} // {{.FieldDesc}}
{{- end}}
}

var {{.FirstLowerName}}List []*{{.FirstUpperName}}
var {{.FirstLowerName}}Map map[int]*{{.FirstUpperName}}

func Get{{.FirstUpperName}}(Sid int) *{{.FirstUpperName}} {
	if v, ok := {{.FirstLowerName}}Map[Sid]; ok {
		return v
	}
	return nil
}

func GetAll{{.FirstUpperName}}() []*{{.FirstUpperName}} {
	result := make([]*{{.FirstUpperName}}, 0)
	for _, c := range {{.FirstLowerName}}List {
		result = append(result, c)
	}
	return result
}

func load{{.FirstUpperName}}(filePath string) {
	xlsx, err := excelize.OpenFile(filePath)
	if err != nil {
		log.Fatal(err)
	}
	sheetName := xlsx.GetSheetName(1)
	rows := xlsx.GetRows(sheetName)

	{{.FirstLowerName}}Map = make(map[int]*{{.FirstUpperName}})
	{{.FirstLowerName}}List = make([]*{{.FirstUpperName}}, 0)

	for _, row := range rows[4:] {
		data := make(map[string]interface{})
		for j, colCell := range row {
			fieldName := rows[1][j]
			if fieldName != "" {
				data[rows[1][j]] = configUtls.GetValueByType(rows[2][j], colCell)
			}
		}
		var config {{.FirstUpperName}}
		err := mapstructure.Decode(data, &config)
		if err != nil {
			log.Fatal(err)
			return
		}

		{{.FirstLowerName}}Map[config.Sid] = &config
		{{.FirstLowerName}}List = append({{.FirstLowerName}}List, &config)
	}
}
`)
	if err != nil {
		fmt.Println(err)
		return
	}

	filePath := goDir + "/" + structInfo.FirstUpperName + ".go"
	file, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Println("文件打开失败", err)
	}
	//及时关闭file句柄
	defer file.Close()
	//写入文件时，使用带缓存的 *Writer
	write := bufio.NewWriter(file)
	err = tmpl.Execute(write, structInfo)
	if err != nil {
		fmt.Println(err)
		return
	}

	//Flush将缓存的文件真正写入到文件中
	write.Flush()
}

func GetStructInfo(xlxsPath string) *StructInfo {
	// 读取 xlsx 文件
	xlsx, err := excelize.OpenFile(xlxsPath)
	if err != nil {
		fmt.Println(err)
		return nil
	}
	fileName := path.Base(xlxsPath)

	// 读取第一个工作表
	sheetName := xlsx.GetSheetName(1)
	rows := xlsx.GetRows(sheetName)

	fields := make([]Field, 0)
	for i, s := range rows[1] {
		if s == "" {
			continue
		}
		FieldDesc := rows[0][i]
		FieldName := rows[1][i]
		Typ := rows[2][i]
		Desc := rows[3][i]
		Commit := "`json:\"" + FieldName + "\"`"

		f := Field{
			FieldDesc: FieldDesc,
			Typ:       Typ,
			Desc:      Desc,
			Commit:    Commit,
			FieldName: stringUtils.FirstUpper(FieldName),
		}
		fields = append(fields, f)
	}
	structName := stringUtils.FirstUpper(sheetName) + "Config"

	// 生成 Go 代码
	structInfo := &StructInfo{
		FirstUpperName: structName,
		FirstLowerName: stringUtils.FirstLower(structName),
		FileName:       fileName,
		Fields:         fields,
	}
	return structInfo
}
